package com.duzq.common.aop;

import com.duzq.common.annotation.EnumValue;
import com.duzq.common.entity.BaseEntity;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

/**
 * 值集转换注解 aop
 *
 * @author duzq
 * @date 2021-03-24 14:51:45
 */
@Component
@Aspect
public class EnumValueAspect {

    /**
     * 在返回之前进行拦截
     */
    @AfterReturning(value = "execution(* com.duzq.controller..*.*(..))", returning = "result")
    public Object enumValue(Object result) {

        // 空返回直接返回
        if (Objects.isNull(result)) {
            return null;
        }

        // list，特殊处理一下
        if (result instanceof List) {
            List list = (List) result;
            for (Object o : list) {
                setEnumValue(o, o.getClass());
            }
            return result;
        }

        // map 特殊处理一下
        if (result instanceof Map) {
            Map map = (Map) result;
            Iterator<Map.Entry> iterator = map.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry next = iterator.next();
                setEnumValue(next.getValue(), next.getValue().getClass());
            }
        }

        // 项目中单个的自定义Bean对象，进行处理
        setEnumValue(result, result.getClass());
        return result;
    }

    /**
     * 开始根据注解，转换值
     *
     * @param result
     */
    private void setEnumValue(Object result, Class clazz) {

        // 不是自己项目中的 bean 直接返回
        if (!(result instanceof BaseEntity)) {
            return;
        }
        // 如果当前的类是 BaseEntity，则不执行后续操作
        if (BaseEntity.class.getName().equals(result.getClass().getName())) {
            return;
        }

        // 1. 获取当前对象的所有字段
        Field[] fields = clazz.getDeclaredFields();
        if (fields == null || fields.length == 0) {
            return;
        }
        // 2. 遍历字段上是否有自定义注解
        for (Field field : fields) {
            try {
                // 通过设置可以访问私有变量的值
                field.setAccessible(true);

                // 字段为空，不执行后续操作
                if (Objects.isNull(field.get(result))) {
                    continue;
                }
                // 判断字段是否为自定义的Java Bean [ 嵌套转换 ]
                if (field.get(result) instanceof BaseEntity) {
                    setEnumValue(field.get(result), field.get(result).getClass());
                }
                // 嵌套的List 循环转换
                if (field.get(result) instanceof List) {
                    List list = (List) field.get(result);
                    if (Objects.isNull(list)) {
                        continue;
                    }
                    for (Object obj : list) {
                        if (obj == null) {
                            continue;
                        }
                        setEnumValue(obj, obj.getClass());
                    }
                }
                // 解析自定义注解
                EnumValue annotation = field.getAnnotation(EnumValue.class);
                if (annotation == null) {
                    continue;
                }
                if (Objects.isNull(annotation.enumType())) {
                    continue;
                }
                // 获取跟CODE编码的名称
                String codeName = getCodeName(annotation.enumType(), field.get(result));
                if (Objects.isNull(codeName)) {
                    continue;
                }
                // 编辑set方法名称
                String setMethodName = null;
                if (!"".equals(annotation.targetField())) {
                    setMethodName = "set" +
                            annotation.targetField().substring(0, 1).toUpperCase() +
                            annotation.targetField().substring(1);
                } else {
                    setMethodName = "set" +
                            field.getName().substring(0, 1).toUpperCase() +
                            field.getName().substring(1) +
                            "Name";
                }
                // 执行set方法
                Method method = result.getClass().getMethod(setMethodName, String.class);
                if (Objects.isNull(method)) {
                    continue;
                }
                method.invoke(result, codeName);
            } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        // 递归获取父类的属性
        setEnumValue(result, clazz.getSuperclass());
    }

    /**
     * 获取跟CODE编码的名称
     *
     * @param enumType
     * @param code
     * @return
     */
    private String getCodeName(String enumType, Object code) {
        // TODO: 查询缓存、或者查询数据库，每个项目不一致，需要维护成自己项目中的代码
        // TODO: 只是为了梳理自定义注解使用的场景，返回值写了固定值。
        return "查询缓存、或者查询数据库";
    }

}
